﻿using System;
using System.Data;

namespace Manso.cBot.Common.Acl
{    
    public class AccessControl
    {
        private readonly AccessConfiguration _accessControlList;                        

        public AccessControl()
        {
            _accessControlList = new AccessConfiguration();
            Load();
        }     
   
        /// <summary>
        /// Read the access control list from xml file
        /// </summary>
        private void Load()
        {                        
            _accessControlList.ReadXml("cBotAccessControlList.xml");              
        }

        /// <summary>
        /// Save the acess control list to xml file
        /// </summary>
        private void Save()
        {
            _accessControlList.WriteXml("cBotAccessControlList.xml");
        }

        /// <summary>
        /// Add or change the level of a character
        /// </summary>
        /// <param name="characterName">Name of the character</param>
        /// <param name="level">Level for the character</param>
        public void Add(String characterName, AccessControlLevel level)
        {            
            bool found = false;
            foreach (AccessConfiguration.CharacterRow row in _accessControlList.Character)
            {
                if (row.Name.ToLower().Equals(characterName.ToLower()))
                {
                    row.Level = GetStringFromLevel(level);
                    found = true;
                }
            }

            if (!found)
            {
                AccessConfiguration.CharacterRow row = _accessControlList.Character.NewCharacterRow();
                row.Name = characterName;
                row.Level = GetStringFromLevel(level);
                _accessControlList.Character.AddCharacterRow(row);
            }
            Save();
        }       

        /// <summary>
        /// Remove character from access control list
        /// </summary>
        /// <param name="characterName">Character name</param>
        public void Remove(String characterName)
        {           
            foreach (AccessConfiguration.CharacterRow row in _accessControlList.Character)
            {
                if (row.Name.ToLower().Equals(characterName.ToLower()))
                {
                    row.Delete();
                    Save();
                    return;
                }
            }            
            throw new Exception("User does not exists on Acl");
        }

        /// <summary>
        /// Retrieve the level for the character
        /// </summary>
        /// <param name="characterName">Name of the character</param>
        /// <returns></returns>
        public AccessControlLevel GetLevelFor(string characterName)
        {
            AccessConfiguration.CharacterDataTable characterTable = _accessControlList.Character;
            foreach (AccessConfiguration.CharacterRow row in characterTable)
            {
                if (row.Name.ToLower().Equals(characterName.ToLower()))
                {
                    return GetLevelFromString(row.Level);
                }
            }            
            return AccessControlLevel.Guest;
        }

        /// <summary>
        /// Gets if the character should be allowed to access the level
        /// </summary>
        /// <param name="characterName">Character name</param>
        /// <param name="level">Level to be checked</param>
        /// <returns>True if user is allowed, otherwise false</returns>
        public bool IsAllowed(string characterName, AccessControlLevel level)
        {
            return (((int) GetLevelFor(characterName)) >= ((int)level));
        }

        /// <summary>
        /// Add or change, if exists, the level of access of the character
        /// </summary>
        /// <param name="characterName"></param>
        /// <param name="level"></param>
        /// <returns></returns>
        public void Add(string characterName, string level)
        {
            Add(characterName, GetLevelFromString(level));
        }

        /// <summary>
        /// Gets self access password
        /// </summary>
        /// <returns>Self access password</returns>
        public String GetSelfAccessPassword()
        {
            //AccessConfiguration selfAccessTable = _accessControlList.SelfAccess;
            AccessConfiguration.SelfAccessDataTable selfAccessTable = _accessControlList.SelfAccess;
            String password = null;
            foreach (AccessConfiguration.SelfAccessRow row in selfAccessTable.Rows)
            {
                password = row.Password;
                break;
            }
            return password;
        }

        private static AccessControlLevel GetLevelFromString(string level)
        {
            switch (level.ToLower())
            {
                case "guest":
                    return AccessControlLevel.Guest;
                case "basic":
                    return AccessControlLevel.Basic;
                case "advance":
                    return AccessControlLevel.Advance;
                case "owner":
                    return AccessControlLevel.Owner;
                default:
                    throw new ArgumentOutOfRangeException();
            }            
        }

        private static String GetStringFromLevel(AccessControlLevel level)
        {
            switch (level)
            {
                case AccessControlLevel.Guest:
                    return "Guest";
                case AccessControlLevel.Basic:
                    return "Basic";
                case AccessControlLevel.Advance:
                    return "Advance";
                case AccessControlLevel.Owner:
                    return "Owner";
                default:
                    throw new ArgumentOutOfRangeException();
            }            
        }                
    }
}
